﻿using System;
using System.Collections.Generic;
using System.Linq;
using MIAP.DataAccess.Interfaces;
using MIAP.DataAccess.SqlServer.Model;
using MIAP.Entidades;
using MIAP.Entidades.Enums;

namespace MIAP.DataAccess.Implementaciones.SQL
{
    /// <summary>
    /// Clase de las operaciones de Acceso a Datos para el módulo de Archivos.
    /// </summary>
    public class ArchivosDao : IArchivosDao
    {
        /// <summary>
        /// Obtiene todos los Archivos.
        /// </summary>
        /// <returns>Lista con todos los Archivos.</returns>
        IList<ArchivoInfo> IArchivosDao.GetArchivos()
        {
            return this.GetArchivosInterno(null, null, null, null, null, null);
        }

        /// <summary>
        /// Obtiene todos los Archivos activos de un proyecto en especifico de un usuario en los que puede cargar información
        /// </summary>
        /// <param name="idProyecto">Es el id del proyecto del cual queremos obtener los archivos relacionados</param>
        /// <param name="idUsuario">Id del usuario a filtrar</param>
        /// <returns>Lista con todos los Archivos.</returns>
        IList<ArchivoInfo> IArchivosDao.GetArchivosCarga(int idProyecto, int idUsuario)
        {
            var archivos = this.GetArchivosInterno(null, idProyecto, null, null, null, true);

            List<int> listIdArchivosAcceso;

            List<ArchivoInfo> listArchivos;

            using (var context = new MIAPDBEntities())
            {
                var query = from archivoAcceso in context.MIAP_USUARIO_ARCHIVO
                            where archivoAcceso.ID_USUARIO == idUsuario && archivoAcceso.ES_CARGA
                            select archivoAcceso.ID_ARCHIVO;

                listIdArchivosAcceso = query.ToList();

                //var listArchivosCargados = from cargaArchivo in context.MIAP_CARGA_ARCHIVO
                //                           join archivo in context.MIAP_ARCHIVO
                //                           on cargaArchivo.ID_ARCHIVO equals archivo.ID_ARCHIVO
                //                           select cargaArchivo;

                listArchivos = (from archivo in archivos
                                where listIdArchivosAcceso.Contains(archivo.IdentificadorArchivo)
                                select archivo).ToList();

                ArchivoInfo listArchivosFinal = new ArchivoInfo();

                // Recorrer los archivos que se encuentran ya cargados.
                //foreach (MIAP_CARGA_ARCHIVO archivo in listArchivosCargados)
                //{
                //    ArchivoInfo archivoInfo = listArchivos.Where(p => p.IdentificadorArchivo == archivo.ID_ARCHIVO && p.EsVersionable == false).SingleOrDefault();

                //    // Remover los archivos ya cargados no versionables. 
                //    if (archivoInfo != null)
                //    {
                //        listArchivos.Remove(archivoInfo);
                //    }
                //}
            }

            return listArchivos;
        }

        /// <summary>
        /// Obtiene todos los Archivos dependiendo del los filtros enviados, si no se requiere el filtro enviar NULL.
        /// </summary>
        /// <param name="nombreArchivo">Nombre delarchivo a buscar</param>
        /// <param name="idProyecto">Es el id del proyecto del cual queremos obtener los archivos relacionados</param>
        /// <param name="idFormatoArchivo">Es el id del formato de archivo</param>
        /// <param name="esObligatorio">True si es obligatorio, false en caso contrario</param>
        /// <param name="esVersion">True si es versión, false en caso contrario</param>
        /// <param name="estaActivo">True si esta activo, false en caso contrario</param>
        /// <returns>Lista con todos los Archivos.</returns>
        IList<ArchivoInfo> IArchivosDao.GetArchivos(string nombreArchivo, int? idProyecto, int? idFormatoArchivo, bool? esObligatorio, bool? esVersion,
                                 bool? estaActivo)
        {
            return this.GetArchivosInterno(nombreArchivo, idProyecto, idFormatoArchivo, esObligatorio, esVersion, estaActivo);
        }

        /// <summary>
        /// metodo privado en donde obtenemos los archivos deseados
        /// </summary>
        /// <param name="nombreArchivo">Nombre del archivo a buscar</param>
        /// <param name="idProyecto">Es el id del proyecto del cual queremos obtener los archivos relacionados</param>
        /// <param name="idFormatoArchivo">Es el id del formato de archivo</param>
        /// <param name="esObligatorio">True si es obligatorio, false en caso contrario</param>
        /// <param name="esVersion">True si es versión, false en caso contrario</param>
        /// <param name="estaActivo">True si esta activo, false en caso contrario</param>
        /// <returns></returns>
        private IList<ArchivoInfo> GetArchivosInterno(string nombreArchivo, int? idProyecto, int? idFormatoArchivo, bool? esObligatorio, bool? esVersion,
                                 bool? estaActivo)
        {
            IList<ArchivoInfo> result;
            var activo = Enum.GetName(typeof(Estatus), Estatus.Activo);
            var inactivo = Enum.GetName(typeof(Estatus), Estatus.Inactivo);
            var si = Enum.GetName(typeof(SiNo), SiNo.Si);
            var no = Enum.GetName(typeof(SiNo), SiNo.No);
            using (var context = new MIAPDBEntities())
            {

                var query = from miapArchivo in context.MIAP_ARCHIVO
                            where (string.IsNullOrEmpty(nombreArchivo) || miapArchivo.NOMBRE.Contains(nombreArchivo))
                            && (idProyecto == null || miapArchivo.ID_PROYECTO == idProyecto)
                            && (!idFormatoArchivo.HasValue || miapArchivo.ID_FORMATO_ARCHIVO == idFormatoArchivo)
                            && (!esObligatorio.HasValue || miapArchivo.OBLIGATORIO == esObligatorio)
                            && (!esVersion.HasValue || miapArchivo.VERSION == esVersion)
                            && (!estaActivo.HasValue || miapArchivo.ACTIVO == estaActivo)
                            select new ArchivoInfo
                            {
                                IdentificadorArchivo = miapArchivo.ID_ARCHIVO,
                                Proyecto = new ProyectoInfo
                            {
                                IDProyecto = miapArchivo.MIAP_PROYECTO.ID_PROYECTO,
                                Descripcion = miapArchivo.MIAP_PROYECTO.DESCRIPCION,
                                Estatus = miapArchivo.MIAP_PROYECTO.ACTIVO ? "Activo" : "Inactivo",
                                NombreProyecto = miapArchivo.MIAP_PROYECTO.NOMBRE,
                                FechaActualizacion = miapArchivo.MIAP_PROYECTO.FECHA_ACTUALIZACION,
                                FechaCreacion = miapArchivo.MIAP_PROYECTO.FECHA_CREACION,
                                PaqueteCarga = miapArchivo.MIAP_PROYECTO.PAQUETE_CARGA,
                                PeriodoCarga = new PeriodoInfo
                                {
                                    IdentificadorPeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_CARGA.ID_PERIODO_CARGA,
                                    NombrePeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_CARGA.NOMBRE,
                                    TipoPeriodo = TipoPeriodo.Carga
                                },
                                PeriodoInformacion = new PeriodoInfo
                                {
                                    IdentificadorPeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_INFORMACION.ID_PERIODO_INFORMACION,
                                    NombrePeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_INFORMACION.NOMBRE,
                                    TipoPeriodo = TipoPeriodo.Informacion
                                }
                            },
                                Descripcion = miapArchivo.DESCRIPCION,
                                EstaActivo = miapArchivo.ACTIVO ? activo : inactivo,
                                NombreArchivo = miapArchivo.NOMBRE,
                                FechaActualizacion = miapArchivo.FECHA_ACTUALIZACION,
                                FechaCreacion = miapArchivo.FECHA_CREACION,
                                EsObligatorio = miapArchivo.OBLIGATORIO ? si : no,
                                EsVersion = miapArchivo.VERSION ? si : no,
                                EsVersionable = miapArchivo.VERSION,
                                EsquemaArchivoXML = miapArchivo.ESQUEMA_ARCHIVO,
                                ProcedimientoCarga = miapArchivo.PROCEDIMIENTO_CARGA,
                                FormatoArchivo = new FormatoArchivoInfo
                                    {
                                        IdentificadorFormatoArchivo = miapArchivo.MIAP_FORMATO_ARCHIVO.ID_FORMATO_ARCHIVO,
                                        NombreFormatoArchivo = miapArchivo.MIAP_FORMATO_ARCHIVO.NOMBRE
                                    }
                            };
                result = query.ToList();
            }

            return result;
        }

        /// <summary>
        /// Cambia el estatus del Archivo a activo o inactivo.
        /// </summary>
        /// <param name="idArchivo">Es el id del Archivo del cual se cambiará el estatus.</param>
        /// <param name="estatusRegistro">True (Activo), False (Inactivo)</param>
        void IArchivosDao.ChangeEstatusArchivo(int idArchivo, bool estatusRegistro)
        {
            using (var context = new MIAPDBEntities())
            {
                var query = (from miapArchivo in context.MIAP_ARCHIVO
                             where miapArchivo.ID_ARCHIVO == idArchivo
                             select miapArchivo).SingleOrDefault();
                if (query == null) return;

                query.ACTIVO = estatusRegistro;
                context.SaveChanges();
            }
        }

        /// <summary>
        /// Obtiene la información de un determinado Archivo.
        /// </summary>
        /// <param name="idArchivo">Es el id del Archivo del que se desea obtener la informacion.</param>
        /// <returns>Información general del Archivo.</returns>
        ArchivoInfo IArchivosDao.GetArchivoById(int idArchivo)
        {
            ArchivoInfo result;
            var activo = Enum.GetName(typeof(Estatus), Estatus.Activo);
            var inactivo = Enum.GetName(typeof(Estatus), Estatus.Inactivo);
            var si = Enum.GetName(typeof(SiNo), SiNo.Si);
            var no = Enum.GetName(typeof(SiNo), SiNo.No);
            using (var context = new MIAPDBEntities())
            {
                var query = (from miapArchivo in context.MIAP_ARCHIVO
                             where miapArchivo.ID_ARCHIVO == idArchivo
                             select new ArchivoInfo
                             {
                                 IdentificadorArchivo = miapArchivo.ID_ARCHIVO,
                                 Proyecto = new ProyectoInfo
                                 {
                                     IDProyecto = miapArchivo.MIAP_PROYECTO.ID_PROYECTO,
                                     Descripcion = miapArchivo.MIAP_PROYECTO.DESCRIPCION,
                                     Estatus = miapArchivo.MIAP_PROYECTO.ACTIVO ? activo : inactivo,
                                     NombreProyecto = miapArchivo.MIAP_PROYECTO.NOMBRE,
                                     FechaActualizacion = miapArchivo.MIAP_PROYECTO.FECHA_ACTUALIZACION,
                                     FechaCreacion = miapArchivo.MIAP_PROYECTO.FECHA_CREACION,
                                     PaqueteCarga = miapArchivo.MIAP_PROYECTO.PAQUETE_CARGA,
                                     PeriodoCarga = new PeriodoInfo
                                     {
                                         IdentificadorPeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_CARGA.ID_PERIODO_CARGA,
                                         NombrePeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_CARGA.NOMBRE,
                                         TipoPeriodo = TipoPeriodo.Carga
                                     },
                                     PeriodoInformacion = new PeriodoInfo
                                     {
                                         IdentificadorPeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_INFORMACION.ID_PERIODO_INFORMACION,
                                         NombrePeriodo = miapArchivo.MIAP_PROYECTO.MIAP_PERIODO_INFORMACION.NOMBRE,
                                         TipoPeriodo = TipoPeriodo.Informacion
                                     }
                                 },
                                 Descripcion = miapArchivo.DESCRIPCION,
                                 EstaActivo = miapArchivo.ACTIVO ? activo : inactivo,
                                 NombreArchivo = miapArchivo.NOMBRE,
                                 FechaActualizacion = miapArchivo.FECHA_ACTUALIZACION,
                                 FechaCreacion = miapArchivo.FECHA_CREACION,
                                 EsObligatorio = miapArchivo.OBLIGATORIO ? si : no,
                                 EsVersion = miapArchivo.VERSION ? si : no,
                                 EsquemaArchivoXML = miapArchivo.ESQUEMA_ARCHIVO,
                                 ProcedimientoCarga = miapArchivo.PROCEDIMIENTO_CARGA,
                                 FormatoArchivo = new FormatoArchivoInfo
                                 {
                                     IdentificadorFormatoArchivo = miapArchivo.MIAP_FORMATO_ARCHIVO.ID_FORMATO_ARCHIVO,
                                     NombreFormatoArchivo = miapArchivo.MIAP_FORMATO_ARCHIVO.NOMBRE
                                 }
                             }).SingleOrDefault();
                result = query;
            }

            return result;
        }

        /// <summary>
        /// Agrega un nuevo Archivo.
        /// </summary>
        /// <param name="archivo">Es el proyecto que será agregado.</param>
        /// <param name="user">Usuario que esta agregando la información.</param>
        /// <param name="usuariosCarga">Usuarios que pueden cargar el archivo.</param>
        void IArchivosDao.AddNewArchivo(ArchivoInfo archivo, string user, List<UsuarioInfo> usuariosCarga)
        {
            var activo = Enum.GetName(typeof(Estatus), Estatus.Activo);
            var si = Enum.GetName(typeof(SiNo), SiNo.Si);
            var idconf = Convert.ToInt32(new ConfiguracionDao().GetConfiguracionPerfilAdministrador().Descripcion);
            using (var context = new MIAPDBEntities())
            {
                var miapProyecto = new MIAP_ARCHIVO
                {
                    ID_PERIODO_CARGA = archivo.PeriodoCarga == null ? (int?)null : archivo.PeriodoCarga.IdentificadorPeriodo,
                    ID_PROYECTO = archivo.Proyecto.IDProyecto,
                    ID_PERIODO_INFORMACION = archivo.PeriodoInformacion == null ? (int?)null : archivo.PeriodoInformacion.IdentificadorPeriodo,
                    ID_FORMATO_ARCHIVO = archivo.FormatoArchivo.IdentificadorFormatoArchivo,
                    ESQUEMA_ARCHIVO = archivo.EsquemaArchivoXML,
                    ACTIVO = archivo.EstaActivo == activo,
                    OBLIGATORIO = archivo.EsObligatorio == si,
                    VERSION = archivo.EsVersion == si,
                    PROCEDIMIENTO_CARGA = archivo.ProcedimientoCarga,
                    NOMBRE = archivo.NombreArchivo,
                    USUARIO_CREACION = user,
                    USUARIO_ACTUALIZACION = user,
                    FECHA_ACTUALIZACION = DateTime.Now,
                    FECHA_CREACION = DateTime.Now,
                    DESCRIPCION = archivo.Descripcion
                };

                context.MIAP_ARCHIVO.Add(miapProyecto);

                var IdAdministradores = (from usuario in context.MIAP_USUARIO_PERFIL
                                         where usuario.ID_PERFIL == idconf
                                         select usuario.ID_USUARIO).ToList();
                //agregamos a los usuarios en la lista excepto a los administradores ya que ellos tendran permisos especiales
                if (usuariosCarga != null && usuariosCarga.Count > 0)
                {
                    foreach (var usuarioInfo in usuariosCarga.Where(usuario => usuario.IsChecked
                        && !IdAdministradores.Contains(usuario.IdUsuario)).ToList())
                    {
                        var miapUsuarioArchivo = new MIAP_USUARIO_ARCHIVO
                            {
                                ID_ARCHIVO = miapProyecto.ID_ARCHIVO,
                                ID_USUARIO = usuarioInfo.IdUsuario,
                                ES_CARGA = true,
                                ES_AUTORIZACION = false,
                                USUARIO_CREACION = user,
                                USUARIO_ACTUALIZACION = user,
                                FECHA_ACTUALIZACION = DateTime.Now,
                                FECHA_CREACION = DateTime.Now,
                            };
                        context.MIAP_USUARIO_ARCHIVO.Add(miapUsuarioArchivo);
                    }
                }
                // Agregamos a los administradores todos los permisos para este nuevo archivo
                foreach (var miapUsuarioArchivo in IdAdministradores.Select(id => new MIAP_USUARIO_ARCHIVO
                    {
                        ID_ARCHIVO = miapProyecto.ID_ARCHIVO,
                        ID_USUARIO = id,
                        ES_CARGA = true,
                        ES_AUTORIZACION = true,
                        USUARIO_CREACION = user,
                        USUARIO_ACTUALIZACION = user,
                        FECHA_ACTUALIZACION = DateTime.Now,
                        FECHA_CREACION = DateTime.Now,
                    }))
                {
                    context.MIAP_USUARIO_ARCHIVO.Add(miapUsuarioArchivo);
                }

                context.SaveChanges();
            }
        }

        /// <summary>
        /// Modifica la información de un Archivo.
        /// </summary>
        /// <param name="archivo">Es el Archivo al que se le modificará la información.</param>
        /// <param name="user">Es el usuario que esta modificando la información.</param>
        /// <param name="usuariosCarga">Usuarios que pueden cargar el archivo.</param>
        void IArchivosDao.EditArchivo(ArchivoInfo archivo, string user, List<UsuarioInfo> usuariosCarga)
        {
            var activo = Enum.GetName(typeof(Estatus), Estatus.Activo);
            var si = Enum.GetName(typeof(SiNo), SiNo.Si);
            using (var context = new MIAPDBEntities())
            {
                var query = (from miapArchivo in context.MIAP_ARCHIVO
                             where miapArchivo.ID_ARCHIVO == archivo.IdentificadorArchivo
                             select miapArchivo).SingleOrDefault();
                if (query == null) return;

                query.NOMBRE = archivo.NombreArchivo;
                query.ACTIVO = archivo.EstaActivo == activo;
                query.OBLIGATORIO = archivo.EsObligatorio == si;
                query.VERSION = archivo.EsVersion == si;
                query.ESQUEMA_ARCHIVO = archivo.EsquemaArchivoXML;
                query.PROCEDIMIENTO_CARGA = archivo.ProcedimientoCarga;
                query.DESCRIPCION = archivo.Descripcion;
                query.ID_PROYECTO = archivo.Proyecto.IDProyecto;
                query.ID_PERIODO_CARGA = archivo.PeriodoCarga == null ? (int?)null : archivo.PeriodoCarga.IdentificadorPeriodo;
                query.ID_PERIODO_INFORMACION = archivo.PeriodoInformacion == null ? (int?)null : archivo.PeriodoInformacion.IdentificadorPeriodo;
                query.ID_FORMATO_ARCHIVO = archivo.FormatoArchivo.IdentificadorFormatoArchivo;
                query.FECHA_ACTUALIZACION = DateTime.Now;
                query.USUARIO_ACTUALIZACION = user;

                if (usuariosCarga != null && usuariosCarga.Count > 0)
                {
                    var listIds = (from usuarioInfo in usuariosCarga select usuarioInfo.IdUsuario).ToList();

                    var queryUsuarios = (from usuarioArchivo in context.MIAP_USUARIO_ARCHIVO
                                         where (usuarioArchivo.ID_ARCHIVO == archivo.IdentificadorArchivo
                                               && listIds.Contains(usuarioArchivo.ID_USUARIO))
                                         select usuarioArchivo).ToList();
                    foreach (var miapUsuarioArchivo in queryUsuarios)
                    {
                        miapUsuarioArchivo.ES_CARGA =
                            usuariosCarga.Single(elemento => elemento.IdUsuario == miapUsuarioArchivo.ID_USUARIO).IsChecked;
                        miapUsuarioArchivo.FECHA_ACTUALIZACION = DateTime.Now;
                        miapUsuarioArchivo.USUARIO_ACTUALIZACION = user;
                    }
                }

                context.SaveChanges();
            }
        }

        /// <summary>
        /// Verifica la existencia de un archivo en un determinado proyecto.
        /// </summary>
        /// <param name="idProyecto">Es el id del proyecto con el que esta ligado el archivo.</param>
        /// <param name="nombreArchivo">Es el nombre del archivo.</param>
        /// <returns>Indicador de si el archivo existe o no y esta ligado al id del proyecto.</returns>
        public bool VerifyExistNombreArchivoInProyecto(int idProyecto, string nombreArchivo)
        {
            using (var context = new MIAPDBEntities())
            {
                var query = from archivo in context.MIAP_ARCHIVO
                            join proyecto in context.MIAP_PROYECTO
                            on archivo.ID_PROYECTO equals proyecto.ID_PROYECTO
                            where (archivo.NOMBRE.Trim().ToLower() == nombreArchivo && proyecto.ID_PROYECTO == idProyecto)
                            select archivo;

                MIAP_ARCHIVO archivoExist = query.SingleOrDefault();

                if (archivoExist != null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
}
